
import std.random;
import std.math;

import std.stdio:writefln;

class Neuron{
	this(int size){
		pi.length = size;
		for(int i = 0; i < size; i++)
			pi[i] = (rand() % 10000) / 10000.0f;
	}

	float pi[];
}


float dist(int x0, int y0, int x1, int y1){
	return sqrt(cast(float)( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) ));
}


class Graph{
	
	this(bool[][] adjM, int _piSize, int maxIterations){
		piSize = _piSize;
		iterations = maxIterations;

		adjacencyMatrix.length = adjM.length;
		for(int i = 0; i < adjacencyMatrix.length; i++)
			adjacencyMatrix[i].length = adjM.length;

		for(int i = 0; i < adjacencyMatrix.length; i++)
				adjacencyMatrix[i][0..$] = adjM[i][0..$];

		neurons.length = adjacencyMatrix.length;
		for(int i = 0; i < neurons.length; i++)
				neurons[i] = new Neuron(piSize);
	}

	float dist(float[] a, float[] b){
		float ret = 0.0f;

		for(int i = 0; i < a.length; i++)
			ret += ((a[i]-b[i]) * (a[i]-b[i]));
		ret = sqrt(ret);

		return ret;
	}

	void updateWeights(float[] pi, float[] ex){
		float alpha = 1.0 - (currentIteration - 1.0) / iterations;
		for(int i = 0; i < pi.length; ++i)
			pi[i] += (alpha * (ex[i] - pi[i]));
	}

	void update(int pos, float[] tmp){
		updateWeights(neurons[pos].pi, tmp);
		for(int i = 0; i < adjacencyMatrix.length; i++)
			if(adjacencyMatrix[pos][i] == 1 || adjacencyMatrix[i][pos] == 1)
				updateWeights(neurons[i].pi, tmp);
	}

	bool train(){
		float[] tmp;
		tmp.length = piSize;

		foreach(inout a;tmp)
			a = (rand() % 10000) / 10000.0f;

		float shortestDistance = float.max;
		int point = -1;

		foreach(int i, neuron; neurons){
			float distance = dist(neuron.pi, tmp);
			if(distance < shortestDistance){
				shortestDistance = distance;
				point = i;
			}
		}
		update(point, tmp);
		currentIteration++;
		if(currentIteration >= iterations)
			return true;
		return false;
	}

	bool[][] adjacencyMatrix = null;
	Neuron[] neurons = null;
	int iterations = 10000;
	int currentIteration = 0;
	int piSize;
}
